package fallingGame;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.Vector;
import javax.swing.JOptionPane;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.xpath.XPath;
import javax.xml.xpath.XPathExpressionException;
import javax.xml.xpath.XPathFactory;

import org.w3c.dom.Document;
import org.xml.sax.SAXException;

/**
 * <p>
 * Title: HighScore
 * </p>
 * <p>
 * Description: CS 343 Course Project HighScore is a class responsible for both
 * recording and loading high score data from the game.
 * </p>
 * 
 * @author Nathanial Howard, Joe Costello, Dustin Schwingle, Jared Potter
 * @email nathanial.howard@my.uwrf.edu, anthony.costello@my.uwrf.edu,
 *        dustin.schwingle@my.uwrf.edu, jared.potter@my.uwrf.edu
 * @date December 01, 2011
 * @team Group 2
 */
public class HighScore {

	/*
	 * External file to be read in
	 */
	private final String DIRECTORY = "src/fallingGame/";
	private final String FILENAME = "HighScore.xml";
	private final String COMPLETE_NAME = DIRECTORY + FILENAME;
	private final String[] headers = { "Name", "Score" };

	private XPath path;
	private Document indoc;
	private DocumentBuilder docbuilder;
	private File infile;

	private JTable table;
	private JScrollPane scroll;
	private Object[][] data;

	/**
	 * HighScore
	 * 
	 * default constructor
	 * @throws ParserConfigurationException
	 *             , SAXException, IOException
	 * @ensure xml file is ready for reading
	 */
	public HighScore() {

		/*
		 * Checks if the xml file exists and if it does not, then it creates it
		 */
		File file = new File(COMPLETE_NAME);
		boolean success = false;
		try {
			success = file.createNewFile();
		} catch (IOException e1) {
			// TODO Auto-generated catch block
			e1.printStackTrace();
		}
		if (success) {
			try {
				FileWriter outFile = new FileWriter(COMPLETE_NAME);
				PrintWriter out = new PrintWriter(outFile);
				out.println("<?xml version='1.0'?>");
				out.println("<highscoredata>");
				out.println("</highscoredata>");
				out.close();
				outFile.close();
			} catch (FileNotFoundException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			} catch (IOException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}

		/*
		 * Set up the file for reading
		 */
		infile = new File(COMPLETE_NAME);
		indoc = null;

		/*
		 * Open the file as an XML file and parse (read) the data within if
		 * possible
		 */
		try {
			docbuilder = DocumentBuilderFactory.newInstance()
					.newDocumentBuilder();
			indoc = docbuilder.parse(infile);
		} catch (ParserConfigurationException e) {
			System.err.println("Not able to create DocumentBuilder object!");
			e.printStackTrace();
		} catch (SAXException e) {
			System.err.println("Not able to read XML file: " + COMPLETE_NAME);
			e.printStackTrace();
		} catch (IOException e) {
			System.err.println("Not able to open file: " + COMPLETE_NAME);
			e.printStackTrace();
		}

		/*
		 * Set up an XPath object so we can navigate the document.
		 */
		path = XPathFactory.newInstance().newXPath();

	}

	/**
	 * clearHighScores
	 * 
	 * Clears the high score table
	 * 
	 * @ensure the high score table will be cleared
	 */
	public void clearHighScores() {
		try {
			FileWriter outFile = new FileWriter(COMPLETE_NAME);
			PrintWriter out = new PrintWriter(outFile);
			out.println("<?xml version='1.0'?>");
			out.println("<highscoredata>");
			out.println("</highscoredata>");
			out.close();
			outFile.close();
		} catch (FileNotFoundException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}

	/**
	 * showHighScores displays the highScore in a JTable
	 * 
	 * @throws NumberFormatException
	 *             , XPathExpressionException
	 * 
	 * @ensure JTable is displayed in the JOptionPane and will have the scores
	 *         sorted in descending order
	 */
	public void showHighScores() {

		String inspectString_Name;
		String inspectString_Score;
		String inspectString_count;
		String name;
		int score;
		int count;

		if (indoc != null && path != null) {

			try {

				inspectString_count = "count(/highscoredata/scoredata)";
				count = Integer.parseInt(path.evaluate(inspectString_count,
						indoc));
				if (count == 0) {
					data = new Object[1][2];
					data[0][0] = "";
					data[0][1] = "";
				} else
					data = new Object[count][2];

				for (int i = 1; i < count + 1; i++) {

					inspectString_Name = "/highscoredata/scoredata[" + i
							+ "]/name";
					inspectString_Score = "/highscoredata/scoredata[" + i
							+ "]/score";

					name = path.evaluate(inspectString_Name, indoc);

					score = Integer.parseInt(path.evaluate(inspectString_Score,
							indoc));

					data[i - 1][0] = name;
					data[i - 1][1] = score;
				}

				data = sort(data, 1);

				table = new MyTable(data, headers);
				scroll = new JScrollPane(table);
				JOptionPane.showMessageDialog(null, scroll, "High Scores",
						JOptionPane.PLAIN_MESSAGE);

			} catch (NumberFormatException e) {
				System.err.println("Not able to read number.");
				e.printStackTrace();
			} catch (XPathExpressionException e) {
				System.err.println("Bad XPath expression.");
				e.printStackTrace();
			}
		} else {
			System.err.println("Cannot inspect document!");
		}
	}

	/**
	 * saveHighScore
	 * 
	 * Save a name and score to an xml file
	 * 
	 * @param name
	 * @param score
	 * @throws IOException
	 * 
	 * @require score > 0 && !name.isEmpty()
	 * 
	 * @ensure XML file will be updated with the new name and score
	 */
	public void saveHighScore(String name, int score) {
		try {
			FileReader input = new FileReader(COMPLETE_NAME);
			BufferedReader br = new BufferedReader(input);
			Vector<String> v = new Vector<String>();
			String line = br.readLine();

			while (line != null) {
				v.add(line);
				line = br.readLine();
			}
			br.close();
			input.close();

			FileWriter outFile = new FileWriter(COMPLETE_NAME);
			PrintWriter out = new PrintWriter(outFile);

			for (int i = 0; i < v.size(); i++) {
				if (i == 2) {
					out.println("<scoredata><name>" + name + "</name><score>"
							+ score + "</score></scoredata>");
					out.flush();
				}
				out.println(v.elementAt(i));
				out.flush();
			}

			out.close();
			outFile.close();
		} catch (IOException e) {
			e.printStackTrace();
		}
	}

	/**
	 * sort
	 * 
	 * sorts the high scores
	 * 
	 * @param array
	 * @param column
	 * @return array of type Object[][]
	 * @require array != null column >= 0
	 * 
	 * @ensure array is sorted in descending order according to the column
	 *         provided
	 */
	public Object[][] sort(Object[][] array, int column) {
		Object[][] temp = new Object[array.length][array[0].length];
		boolean finished = false;
		while (!finished) {
			finished = true;
			for (int i = 0; i < array.length - 1; i++) {
				int x = (Integer) array[i][column];
				int y = (Integer) array[i + 1][column];
				if (x < y) {
					for (int j = 0; j < array[i].length; j++) {
						temp[i][j] = array[i][j];
						array[i][j] = array[i + 1][j];
						array[i + 1][j] = temp[i][j];
					}
					finished = false;
				}
			}
		}
		return array;
	}
}
